package ooo.reindeer.commons.utils;

import ooo.reindeer.logging.ILogger;
import ooo.reindeer.logging.LogUtil;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Consumer;

/**
 * @ClassName Timestamp
 * @Author songbailin
 * @Date 2019/9/23 11:37
 * @Version 1.0
 * @Description TODO
 */
public class Timestamp {

    protected static final ILogger logger = LogUtil.getLogger(Timestamp.class);

    final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();

    TimeUnit periodicUnit = TimeUnit.SECONDS;
    long periodic = 1;

    volatile long lastTime = 0;
    volatile long nowTime = 0;

    final AtomicInteger timestamp = new AtomicInteger(generateTimestamp());

    Consumer<Long> function;

    TimeUnit baseTimeUnit = TimeUnit.MILLISECONDS;

    Thread updateTimestampThread = new Thread(new Runnable() {

        @Override
        public void run() {

            long use=0;
            long poorSleep=0;
            long baseTime = baseTimeUnit.convert(periodic, periodicUnit);

            long expectedSleep=1000;

            long  avgPorSleep=0;
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    baseTimeUnit.sleep(baseTime-use);

                    LOCK.writeLock().lock();
                    lastTime=System.currentTimeMillis();
                    function.accept((long) timestamp.get());
                    use=System.currentTimeMillis()-lastTime;
                    timestamp.set(generateTimestamp());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    LOCK.writeLock().unlock();

                }
            }
        }
    });

    public Timestamp(Consumer<Long> function) {
        this.function = function;
        updateTimestampThread.setName("Update-Timestamp-Thread");
        updateTimestampThread.setDaemon(true);
        updateTimestampThread.start();
    }


    private int generateTimestamp() {

        nowTime=System.currentTimeMillis();
        return (int) (nowTime / TimeUnit.MILLISECONDS.convert(periodic, periodicUnit));
    }


    public long getPeriodic() {
        return periodic;
    }

    public void setPeriodic(long periodic) {
        this.periodic = periodic;
    }

    public TimeUnit getPeriodicUnit() {
        return periodicUnit;
    }

    public void setPeriodicUnit(TimeUnit periodicUnit) {
        this.periodicUnit = periodicUnit;
    }

    public int getTimestamp() {
        return timestamp.get();
    }

}
